//g
import java.util.HashMap;

import utils.myVector;

import GameObjects.*;
import GamePhysics.PhysicsHandler;

import com.jme.app.BaseGame;
import com.jme.renderer.*;
import com.jme.scene.*;
import com.jme.math.*;
import com.jme.bounding.*;
import com.jme.scene.shape.*;
import com.jme.scene.state.*;
import com.jme.system.*;
import com.jme.image.*;
import com.jme.input.*;
import com.jme.input.thirdperson.ThirdPersonMouseLook;
import com.jme.util.*;
import com.jmex.terrain.TerrainBlock;


//// PHIL COMMIT WORKS

public class ConanCore extends BaseGame {
	final private int NUMTEXTURES = 3;
	final private String TEXTURE_PATH = "data/";
	final private String [] PLANET_TEXTURE_NAMES= {"moonmap1k.jpg", "earthmap1k.jpg", "earthights1k.jpg" };
	private int width, height, depth, freq;
	private boolean fullscreen;
	private Camera cam;
	protected Timer timer;
	private boolean freecamera = true;
	private ChaseCamera chaser;
	private TerrainBlock tb;

	//the root node of the scene graph
	private Node scene;
	//TextureState to show the monkey on the sphere.
	private TextureState ts;
	protected InputHandler input;
	
	
	///// GAME VARIABLES
	private GameObjectManager objectStorage;
	private PhysicsHandler physicsCalculator;

	
	///////////////////////////////////////////////////////////////////////////////////////////////////////// MAIN
	public static void main(String[] args) 
	{
		ConanCore app = new ConanCore();
		app.setConfigShowMode(ConfigShowMode.AlwaysShow, 
		ConanCore.class.getClassLoader().getResource("data/header.jpg"));
		app.start();
	}
	 
	///////////////////////////////////////////////////////////////////////////////////////////////////////// UPDATE
	//updating scene, calculations etc.
	protected void update(float interpolation) {
        timer.update();
        interpolation = timer.getTimePerFrame();
        
        input.update(interpolation);
        chaser.update(interpolation);
        physicsCalculator.update(interpolation);
        
        cam.setLocation(new Vector3f(objectStorage.getPlayer().getLocation().x, 50, objectStorage.getPlayer().getLocation().y));
        
        
        if (KeyBindingManager.getKeyBindingManager().isValidCommand("exit")) {
            finished = true;
        }
 
        scene.updateGeometricState(interpolation, true);

	}
	 
	///////////////////////////////////////////////////////////////////////////////////////////////////////// RENDER
	//cleans buffers, draws scene
	protected void render(float interpolation) {
		//Clear the screen
		display.getRenderer().clearBuffers();
		display.getRenderer().draw(scene);
	}
	
	
	
	
	
	
	 
	///////////////////////////////////////////////////////////////////////////////////////////////////////// INIT SYSTEM
	//setting window size, bg color, creating window, setting cam perspective, position, up, etc. , 
	//initializing timer, setting keys
	protected void initSystem() 
	{
		//store the properties information
		width = this.settings.getWidth();
		height = this.settings.getHeight();
		depth = this.settings.getDepth();
		freq = this.settings.getFrequency();
		fullscreen = this.settings.isFullscreen();
		try {
			display = DisplaySystem.getDisplaySystem(this.getNewSettings().getRenderer());
			display.createWindow(width, height, depth, freq, fullscreen);
			cam = display.getRenderer().createCamera(width, height);
		} catch (JmeException e) {
			e.printStackTrace();
			System.exit(1);
		}
		
		//set background color
		display.getRenderer().setBackgroundColor(ColorRGBA.black);
		
		//initialize the camera
		cam.setFrustumPerspective(45.0f, (float) width / (float) height, 1,1000);
		Vector3f loc = new Vector3f(0.0f, 20.0f, 50.0f);
		Vector3f left = new Vector3f(-1.0f, 0.0f, 0.0f);
		Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
		Vector3f dir = new Vector3f(0.0f, 0.0f, -1.0f);

		// Move our camera to a correct place and orientation.
		cam.setFrame(loc, left, up, dir);
		/** Signal that we've changed our camera's location/frustum. */
		cam.update();
		/** Get a high resolution timer for FPS updates. */
		timer = Timer.getTimer();
		display.getRenderer().setCamera(cam);
	
		KeyBindingManager.getKeyBindingManager().set("exit",
		KeyInput.KEY_ESCAPE);
	}
	///////////////////////////////////////////////////////////////////////////////////////////////////////// INIT GAME
	//setting cull, creating scene, render state, adding objects in the game
	protected void initGame() 
	{
		// Initialize game objects
		objectStorage = GameObjectManager.getGameObjectManager();
		
		// Initialize game physics
		physicsCalculator = PhysicsHandler.getPhysics();
		
		
		scene = new Node("Scene graph node");
		//do not draw back facing triangles since they are invisible by the player anyway
		CullState cs = display.getRenderer().createCullState();
		cs.setCullFace(CullState.Face.Back);
		scene.setRenderState(cs);

		
		ZBufferState buf = display.getRenderer().createZBufferState();
		buf.setEnabled(true);
		buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
		scene.setRenderState(buf);		
		
		buildAxisGrid();
		buildPlayer();
		buildEnemies();
		buildChaseCamera();
		buildInput();
		 
		 
		//update the scene graph for rendering
		scene.updateGeometricState(0.0f, true);  //called when a  new node is added , removed, translated etc.
		scene.updateRenderState();				//called when render state is changed, (new texture state etc.)
	}



	///////////////////////////////////////////////////////////////////////////////////////////////////////// REINIT
	//when the resolution changes
	protected void reinit() {
	   display.recreateWindow(width, height, depth, freq, fullscreen);
	}
	//called in shutdown
	protected void cleanup() {
		ts.deleteAll();

	}
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BUILD GAME ELEMENTS

	///////////////////////////////////////////////////////////////////////////////////////////////////////// BUILD CHASE CAM
    private void buildChaseCamera() {
    	Vector3f targetOffset = new Vector3f();
        targetOffset.y = ((BoundingBox) objectStorage.getPlayer().getWorldBound()).yExtent * 1.5f;
        HashMap<String, Object> props = new HashMap<String, Object>();
        props.put(ThirdPersonMouseLook.PROP_MAXROLLOUT, "6");
        props.put(ThirdPersonMouseLook.PROP_MINROLLOUT, "3");
        props.put(ThirdPersonMouseLook.PROP_MAXASCENT, ""+45 * FastMath.DEG_TO_RAD);
        props.put(ChaseCamera.PROP_INITIALSPHERECOORDS, new Vector3f(5, 0, 30 * FastMath.DEG_TO_RAD));
        props.put(ChaseCamera.PROP_TARGETOFFSET, targetOffset);
        chaser = new ChaseCamera(cam, objectStorage.getPlayer(), props);
        chaser.setMaxDistance(80);
        chaser.setMinDistance(20);
    }

	///////////////////////////////////////////////////////////////////////////////////////////////////////// BUILD INPUT
	private void buildInput()
	{
		input = new ConanInputHandler(objectStorage.getPlayer(), settings.getRenderer());
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////////////// BUILD PLAYER
	private void buildPlayer() {
		objectStorage.addPlayer(scene);
	}
	///////////////////////////////////////////////////////////////////////////////////////////////////////// BUILD ENEMIES
	private void buildEnemies() {
		objectStorage.addEnemy(scene)
		;
		
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////////////// BUILD AXIS GRID	
	private void buildAxisGrid()
	{
		//draw the axis and the grid
		AxisGrid axisGrid = new AxisGrid();
		scene.attachChild(axisGrid.buildGeometry());
	}
}